TypeScript'in gelişmiş string manipülasyonu, kalıp eşleştirme ve doğrulama için güçlü şablon literal tiplerini keşfedin. Pratik örnekler ve gerçek dünya kullanım senaryolarıyla öğrenin.
Şablon Literal Tipleri: TypeScript'te String Kalıp Eşleştirme ve Doğrulama
TypeScript'in tip sistemi sürekli olarak gelişiyor ve geliştiricilere karmaşık mantığı ifade etmek ve tip güvenliğini sağlamak için daha güçlü araçlar sunuyor. Son sürümlerde tanıtılan en ilginç ve çok yönlü özelliklerden biri şablon literal tipleridir. Bu tipler, stringleri tip seviyesinde işlemenize olanak tanıyarak gelişmiş string kalıp eşleştirme ve doğrulama sağlar. Bu, daha sağlam ve sürdürülebilir uygulamalar oluşturmak için yepyeni bir olasılıklar dünyasının kapılarını açar.
Şablon Literal Tipleri Nelerdir?
Şablon literal tipleri, JavaScript'teki şablon literallerinin çalışma şekline benzer şekilde, string literal tipleri ve birleşim tiplerini birleştirerek oluşturulan bir tip biçimidir. Ancak, çalışma zamanı stringleri oluşturmak yerine, mevcut olanlara dayalı olarak yeni tipler oluştururlar.
İşte temel bir örnek:
type Greeting<T extends string> = `Merhaba, ${T}!`;
type MyGreeting = Greeting<"World">; // type MyGreeting = "Merhaba, World!"
Bu örnekte, `Greeting`, bir string tipi olan `T`'yi girdi olarak alan ve "Merhaba, ", `T` ve "!" birleşiminden oluşan yeni bir tip döndüren bir şablon literal tipidir.
Temel String Kalıp Eşleştirme
Şablon literal tipleri, temel string kalıp eşleştirme gerçekleştirmek için kullanılabilir. Bu, yalnızca belirli bir kalıpla eşleşmeleri durumunda geçerli olan tipler oluşturmanıza olanak tanır.
Örneğin, yalnızca "prefix-" ile başlayan stringleri kabul eden bir tip oluşturabilirsiniz:
type PrefixedString<T extends string> = T extends `prefix-${string}` ? T : never;
type ValidPrefixedString = PrefixedString<"prefix-valid">; // type ValidPrefixedString = "prefix-valid"
type InvalidPrefixedString = PrefixedString<"invalid">; // type InvalidPrefixedString = never
Bu örnekte, `PrefixedString`, girdi stringi `T`'nin "prefix-" ile başlayıp başlamadığını kontrol etmek için koşullu bir tip kullanır. Eğer başlıyorsa, tipin kendisi `T`'dir; aksi takdirde, `never`'dır. `never`, TypeScript'te hiçbir zaman oluşmayan değerlerin tipini temsil eden özel bir tiptir ve geçersiz stringi etkili bir şekilde dışlar.
Bir Stringin Parçalarını Çıkarma
Şablon literal tipleri, bir stringin parçalarını çıkarmak için de kullanılabilir. Bu, özellikle stringlerden veri ayrıştırmanız ve farklı tiplere dönüştürmeniz gerektiğinde kullanışlıdır.
Diyelim ki "x:10,y:20" biçiminde bir koordinatı temsil eden bir stringiniz var. x ve y değerlerini çıkarmak için şablon literal tiplerini kullanabilirsiniz:
type CoordinateString = `x:${number},y:${number}`;
type ExtractX<T extends CoordinateString> = T extends `x:${infer X},y:${number}` ? X : never;
type ExtractY<T extends CoordinateString> = T extends `x:${number},y:${infer Y}` ? Y : never;
type XValue = ExtractX<"x:10,y:20">; // type XValue = 10
type YValue = ExtractY<"x:10,y:20">; // type YValue = 20
Bu örnekte, `ExtractX` ve `ExtractY`, `number` tipiyle eşleşen stringin parçalarını yakalamak için `infer` anahtar kelimesini kullanır. `infer`, bir kalıp eşleşmesinden bir tip çıkarmanıza olanak tanır. Yakalanan tipler daha sonra koşullu tipin dönüş tipi olarak kullanılır.
Gelişmiş String Doğrulama
Şablon literal tipleri, gelişmiş string doğrulaması gerçekleştirmek için birleşim tipleri ve koşullu tipler gibi diğer TypeScript özellikleriyle birleştirilebilir. Bu, stringlerin yapısı ve içeriği üzerinde karmaşık kurallar uygulayan tipler oluşturmanıza olanak tanır.
Örneğin, ISO 8601 tarih stringlerini doğrulayan bir tip oluşturabilirsiniz:
type Year = `${number}${number}${number}${number}`;
type Month = `0${number}` | `10` | `11` | `12`;
type Day = `${0}${number}` | `${1 | 2}${number}` | `30` | `31`;
type ISODate = `${Year}-${Month}-${Day}`;
type ValidDate = ISODate extends "2023-10-27" ? true : false; // true
type InvalidDate = ISODate extends "2023-13-27" ? true : false; // false
function processDate(date: ISODate) {
// Function logic here. TypeScript enforces the ISODate format.
return `Processing date: ${date}`;
}
console.log(processDate("2024-01-15")); // Works
//console.log(processDate("2024-1-15")); // TypeScript error: Argument of type '"2024-1-15"' is not assignable to parameter of type '`${number}${number}${number}${number}-${0}${number}-${0}${number}` | `${number}${number}${number}${number}-${0}${number}-${1}${number}` | ... 14 more ... | `${number}${number}${number}${number}-12-31`'.
Burada, `Year`, `Month` ve `Day`, tarihin her bölümü için geçerli biçimleri temsil etmek üzere şablon literal tipleri kullanılarak tanımlanır. `ISODate` daha sonra geçerli bir ISO 8601 tarih stringini temsil eden bir tip oluşturmak için bu tipleri birleştirir. Örnek ayrıca, bu tipin bir fonksiyonda veri biçimlendirmesini zorlamak için nasıl kullanılabileceğini, yanlış tarih biçimlerinin geçirilmesini önlediğini de gösterir. Bu, kodun güvenilirliğini artırır ve geçersiz girişten kaynaklanan çalışma zamanı hatalarını önler.
Gerçek Dünya Kullanım Senaryoları
Şablon literal tipleri çeşitli gerçek dünya senaryolarında kullanılabilir. İşte birkaç örnek:
- Form Doğrulama: E-posta adresleri, telefon numaraları ve posta kodları gibi form girişlerinin biçimini doğrulamak için şablon literal tiplerini kullanabilirsiniz.
- API İstek Doğrulama: API istek yüklerinin yapısını doğrulamak ve beklenen biçime uygun olmalarını sağlamak için şablon literal tiplerini kullanabilirsiniz. Örneğin, bir para birimi kodunu (örn. "USD", "EUR", "GBP") doğrulamak.
- Yapılandırma Dosyası Ayrıştırma: Yapılandırma dosyalarını ayrıştırmak ve belirli kalıplara göre değerleri çıkarmak için şablon literal tiplerini kullanabilirsiniz. Bir yapılandırma nesnesindeki dosya yollarını doğrulamayı düşünün.
- String Tabanlı Enumlar: Şablon literal tiplerini kullanarak doğrulama ile string tabanlı enumlar oluşturabilirsiniz.
Örnek: Para Birimi Kodlarını Doğrulama
Para birimi kodlarını doğrulamanın daha ayrıntılı bir örneğine bakalım. Uygulamamızda yalnızca geçerli ISO 4217 para birimi kodlarının kullanılmasını sağlamak istiyoruz. Bu kodlar genellikle üç büyük harftir.
type CurrencyCode = `${Uppercase<string>}${Uppercase<string>}${Uppercase<string>}`;
function formatCurrency(amount: number, currency: CurrencyCode) {
// Function logic to format currency based on the provided code.
return `$${amount} ${currency}`;
}
console.log(formatCurrency(100, "USD")); // Works
//console.log(formatCurrency(100, "usd")); // TypeScript error: Argument of type '"usd"' is not assignable to parameter of type '`${Uppercase}${Uppercase}${Uppercase}`'.
//More precise example:
type ValidCurrencyCode = "USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD"; // Extend as needed
type StronglyTypedCurrencyCode = ValidCurrencyCode;
function formatCurrencyStronglyTyped(amount: number, currency: StronglyTypedCurrencyCode) {
return `$${amount} ${currency}`;
}
console.log(formatCurrencyStronglyTyped(100, "EUR")); // Works
//console.log(formatCurrencyStronglyTyped(100, "CNY")); // TypeScript error: Argument of type '"CNY"' is not assignable to parameter of type '"USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD"'.
Bu örnek, yalnızca üç büyük harften oluşan stringleri kabul eden bir `CurrencyCode` tipinin nasıl oluşturulacağını gösterir. İkinci, daha güçlü tiplendirilmiş örnek, bunu önceden tanımlanmış kabul edilebilir para birimleri listesiyle daha da nasıl kısıtlayacağınızı gösterir.
Örnek: API Uç Nokta Yollarını Doğrulama
Başka bir kullanım senaryosu da API uç nokta yollarını doğrulamaktır. İsteklerin doğru yollara yapılmasını sağlayarak, geçerli bir API uç nokta yapısını temsil eden bir tip tanımlayabilirsiniz. Bu, özellikle birden çok hizmetin farklı API'ler sunabileceği mikro hizmet mimarilerinde kullanışlıdır.
type APIServiceName = "users" | "products" | "orders";
type APIEndpointPath = `/${APIServiceName}/${string}`;
function callAPI(path: APIEndpointPath) {
// API call logic
console.log(`Calling API: ${path}`)
}
callAPI("/users/123"); // Valid
callAPI("/products/details"); // Valid
//callAPI("/invalid/path"); // TypeScript error
// Even more specific:
type APIAction = "create" | "read" | "update" | "delete";
type APIEndpointPathSpecific = `/${APIServiceName}/${APIAction}`;
function callAPISpecific(path: APIEndpointPathSpecific) {
// API call logic
console.log(`Calling specific API: ${path}`)
}
callAPISpecific("/users/create"); // Valid
//callAPISpecific("/users/list"); // TypeScript error
Bu, API uç noktalarının yapısını daha hassas bir şekilde tanımlamanıza, yazım hatalarını önlemenize ve uygulamanız genelinde tutarlılık sağlamanıza olanak tanır. Bu temel bir örnektir; sorgu parametrelerini ve URL'nin diğer bölümlerini doğrulamak için daha karmaşık kalıplar oluşturulabilir.
Şablon Literal Tiplerini Kullanmanın Faydaları
String kalıp eşleştirme ve doğrulama için şablon literal tiplerini kullanmak çeşitli faydalar sunar:
- Geliştirilmiş Tip Güvenliği: Şablon literal tipleri, stringler üzerinde daha katı tip kısıtlamaları uygulamanıza olanak tanıyarak çalışma zamanı hataları riskini azaltır.
- Gelişmiş Kod Okunabilirliği: Şablon literal tipleri, stringlerin beklenen biçimini açıkça ifade ederek kodunuzu daha okunabilir hale getirir.
- Artan Sürdürülebilirlik: Şablon literal tipleri, string doğrulama kuralları için tek bir kaynak sağlayarak kodunuzu daha sürdürülebilir hale getirir.
- Daha İyi Geliştirici Deneyimi: Şablon literal tipleri, daha iyi otomatik tamamlama ve hata mesajları sağlayarak genel geliştirici deneyimini iyileştirir.
Sınırlamalar
Şablon literal tipleri güçlü olmasına rağmen, bazı sınırlamaları da vardır:
- Karmaşıklık: Şablon literal tipleri, özellikle karmaşık kalıplarla uğraşırken karmaşık hale gelebilir. Tip güvenliğinin faydalarını kod sürdürülebilirliği ile dengelemek çok önemlidir.
- Performans: Şablon literal tipleri, özellikle büyük projelerde derleme performansını etkileyebilir. Bunun nedeni, TypeScript'in daha karmaşık tip denetimi yapması gerekmesidir.
- Sınırlı Düzenli İfade Desteği: Şablon literal tipleri kalıp eşleştirmeye izin verirken, düzenli ifadelerin tüm yelpazesini desteklemez. Yüksek düzeyde karmaşık string doğrulaması için, uygun girdi temizliği için bu tip yapılarıyla birlikte çalışma zamanı düzenli ifadeleri hala gerekebilir.
En İyi Uygulamalar
Şablon literal tiplerini kullanırken akılda tutulması gereken bazı en iyi uygulamalar şunlardır:
- Basit Başlayın: Basit kalıplarla başlayın ve gerektiğinde karmaşıklığı kademeli olarak artırın.
- Açıklayıcı Adlar Kullanın: Kod okunabilirliğini artırmak için şablon literal tipleriniz için açıklayıcı adlar kullanın.
- Tiplerinizi Belgeleyin: Amaçlarını ve kullanımlarını açıklamak için şablon literal tiplerinizi belgeleyin.
- Kapsamlı Bir Şekilde Test Edin: Beklendiği gibi davrandıklarından emin olmak için şablon literal tiplerinizi kapsamlı bir şekilde test edin.
- Performansı Göz Önünde Bulundurun: Şablon literal tiplerinin derleme performansı üzerindeki etkisini göz önünde bulundurun ve kodunuzu buna göre optimize edin.
Sonuç
Şablon literal tipleri, TypeScript'te tip seviyesinde gelişmiş string manipülasyonu, kalıp eşleştirme ve doğrulama gerçekleştirmenize olanak tanıyan güçlü bir özelliktir. Şablon literal tiplerini kullanarak daha sağlam, sürdürülebilir ve tip açısından güvenli uygulamalar oluşturabilirsiniz. Bazı sınırlamaları olmasına rağmen, şablon literal tiplerini kullanmanın faydaları genellikle dezavantajlarından daha ağır basar ve bu da onları herhangi bir TypeScript geliştiricisinin cephaneliğinde değerli bir araç haline getirir. TypeScript dili gelişmeye devam ederken, bu gelişmiş tip özelliklerini anlamak ve kullanmak, yüksek kaliteli yazılımlar oluşturmak için çok önemli olacaktır. Karmaşıklığı okunabilirlikle dengelemeyi ve her zaman kapsamlı testlere öncelik vermeyi unutmayın.